use std::time::Duration;

use honeybee::prelude::*;
use honeybee::Result;

use super::users;

pub struct WaitOnlineUserActor {
    users_addr: Addr<users::Users>,
    old_user_session_key: String,
    _uid: i64,
    session: u32,
    stream: Addr<TcpStreamActor>,
    success: bool,
}

impl WaitOnlineUserActor {
    pub fn new(
        users_addr: Addr<users::Users>,
        old_user_session_key: String,
        uid: i64,
        session: u32,
        stream: Addr<TcpStreamActor>,
    ) -> Self {
        Self {
            users_addr,
            old_user_session_key,
            _uid: uid,
            session,
            stream,
            success: false,
        }
    }
}

#[async_trait::async_trait]
impl Actor for WaitOnlineUserActor {
    fn name(&self) -> &str {
        "WaitOnlineUser"
    }

    async fn started(&mut self, ctx: &mut Context<Self>) -> Result<()> {
        let _ = ctx.send_later(OnlineDirect, Duration::from_secs(7));
        Ok(())
    }

    async fn stopped(&mut self, _ctx: &mut Context<Self>) {
        //如果我(第二个玩家)等待第一个玩家下线的时候，又有第三个同一玩家来登录
        //则通知第二个玩家上线失败，第三个玩家会在新的WaitOnlineUserActor里等第一个玩家下线后再上线
        if !self.success {
            let _ = self.stream.send(SendMsg {
                session: self.session,
                msg: RpcResponse::<()>(Err(RpcResponseError::RpcError("online failed".into()))),
            });
        }
    }
}

#[message]
pub struct ResetStream(pub Addr<TcpStreamActor>);
#[async_trait::async_trait]
impl Handler<ResetStream> for WaitOnlineUserActor {
    async fn handle(&mut self, _ctx: &mut Context<Self>, msg: ResetStream) -> Result<()> {
        self.stream = msg.0;
        Ok(())
    }
}

#[message]
struct OnlineDirect;
#[async_trait::async_trait]
impl Handler<OnlineDirect> for WaitOnlineUserActor {
    async fn handle(&mut self, ctx: &mut Context<Self>, _: OnlineDirect) -> Result<()> {
        self.success = true;
        let _ = self.stream.send(SendMsg {
            session: self.session,
            msg: RpcResponse::<()>(Ok(())),
        });
        let _ = self.users_addr.send(users::RemoveWaitOnlineUser(
            self.old_user_session_key.clone(),
        ));
        ctx.stop(None);
        Ok(())
    }
}

#[message]
pub struct KickoutOldUserSesscss;
#[async_trait::async_trait]
impl Handler<KickoutOldUserSesscss> for WaitOnlineUserActor {
    async fn handle(&mut self, _ctx: &mut Context<Self>, _: KickoutOldUserSesscss) -> Result<()> {
        self.success = true;
        let _ = self.stream.send(SendMsg {
            session: self.session,
            msg: RpcResponse::<()>(Ok(())),
        });
        Ok(())
    }
}
